package io.noties.markwon.plugin.replacement

import org.commonmark.node.AbstractVisitor
import org.commonmark.node.Node
import org.commonmark.node.Text
import org.commonmark.parser.PostProcessor
import java.util.regex.Matcher
import java.util.regex.Pattern


class ReplacementPostProcessor(
    private val mReplacementMap: Map<String, String>,
    keysPattern: Pattern
) :PostProcessor {
    private val mKeysMatcher: Matcher

    init {
        mKeysMatcher = keysPattern.matcher("")
    }

    override fun process(node: Node): Node {
        val replacementVisitor: ReplacementVisitor = ReplacementVisitor()
        node.accept(replacementVisitor)
        return node
    }

    private fun replace(text: Text) {
        val literal = text.literal
        val matcher = mKeysMatcher.reset(literal)
        var lastNode: Node = text
        var last = 0
        while (matcher.find()) {
            val shortcut = matcher.group()
            if (matcher.start() != last) {
                lastNode = insertNode(Text(literal.substring(last, matcher.start())), lastNode)
            }
            val replacementNode = Text(mReplacementMap[shortcut])
            lastNode = insertNode(replacementNode, lastNode)
            last = matcher.end()
        }
        if (last != literal.length) {
            insertNode(Text(literal.substring(last)), lastNode)
        }
        text.unlink()
    }

    private fun insertNode(node: Node, insertAfterNode: Node): Node {
        insertAfterNode.insertAfter(node)
        return node
    }

    private inner class ReplacementVisitor : AbstractVisitor() {
        override fun visit(text: Text) {
            replace(text)
        }
    }
}